/**
 * lwt_core.h: contains core functions that are needed
 * by the lwt library.
 * This is the core header file, no user should include this one.
 *
 * include required functions:
 * void __lwt_schedule(void)
 * void __lwt_dispatch(lwt_t next, lwt_t current)
 * void __lwt_trapoline
 * void __lwt_start(lwt_fn_t fn, void* data)
 *
 * and some necessary functions:
 * int __init_pool()
 *
 */

#ifndef __LWT_CORE_H__
#define __LWT_CORE_H__

#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include "lwt_types.h"


/**
 * TODO: to be modified
 * There are 2 ways to manipulate the pool list.
 *
 * The first one is the most strait forward one, make every thread
 * a node, when a new thread has been created, just create a new 
 * node at the very end of the linked list; when a thread dead, remove
 * it from the linked list.
 * Pros: easy to implement, easy to maintain;
 * Cons: it's just slow to do this. Every create/remove takes a lot memory
 * operations. If we want to get a thread from id, we have to go through the
 * whole linked list.
 *
 * The second way is, when a thread dead, we do not remove it's tcb out
 * of linked list, and do not free the memory it used (like stack), just
 * marked the thread as DEAD and clean all it's memory (make 0s). I also need to 
 * maintain a dead_queue in tcb. When we need to create a new thread, 
 * just go through the dead_queue, and reuse the first node in the dead queue.
 * Pros: would be super effictive certain circumstance, like frequently creating
 * and destorying a lot threads. and it's very easy to get lwt_t from lwt_id. 
 * Cons: User sometime can gain same efficiency under method 1 with reusing created
 * threads; we need to check the length of dead_queue make sure it's not too long, 
 * otherwise there would be too much space waste.
 *
 * I'll try to use the second way.
 *
 */
//this is the pointer to the root node.
//we want to make the main thread tcb root.
//the lwt pool is a linked list, with max size _LWT_POOL_MAX;
_lwt_tcb lwt_lst_root[_LWT_SIZE];
//This is the pointer to the tail node.
int lwt_lst_tail;
//we have a ready queue:
//the ready queue is a linklist, with max size _LWT_RQUEUE_MAX;
//we will not build a seperate run queue, this will simply be
//a pointer to the first lwt_tcb in the run queue.
//We currently useing the FIFO schedule strategy.
int lwt_rdyq_head;
int lwt_rdyq_tail;
//we have a dead queue, for reuse:
int lwt_dead_head;
int lwt_dead_tail;



//the num_of_threads is used to present the number of threads 
//currently in RDY, RUN, and WAIT status. The locked is to protect
//the num_of_threads from multi-thread issue in the next version.
//Only scheduler can access this number, no other thread shouhld be 
//able to access this number, otherwise the number might be wrong.
//Since in the very first version, it is co-operative multi-thread, we
//as long as one does not calls yield, then others will not interrupt
//the process of number modification.
int num_of_threads = 0;
int length_of_rdyq = 0;
int length_of_deadq = 0;

int current_tid = 0;

void __lwt_remove_from_rdyq_S(lwt_t target);
void __lwt_dispatch(_lwt_tcb* next_tcb, _lwt_tcb* curr_tcb);


//this function get the next avaliable tcb number
	static inline
lwt_t __lwt_get_target()
{
	if(lwt_dead_head == _LWT_NULL)
	{
#ifdef DBG
		printf("selected %d because dead_head is NULL\n", num_of_threads);
#endif
		return num_of_threads;
	}
	else
	{
#ifdef DBG
		printf("selected %d because dead_head is %d\n", lwt_dead_head, lwt_dead_head);
#endif
		return lwt_dead_head;
	}
}

void* __lwt_start(lwt_fn_t fn, void* data)
{
#ifdef DBG
	printf("thread %d: __lwt_start\n", current_tid);
#endif

	return fn(data);
}





/**
 *	Remove a node from rdyq
 */
	static inline 
void __lwt_remove_from_rdyq(lwt_t target)
{
#ifdef DBG
	printf("thread %d: __lwt_rmv_rdyq:\t%d\n", current_tid, target);
#endif
//	assert(length_of_rdyq>0);
	if(length_of_rdyq <= 0)
	{
		printf("length_of_rdyq <= 0.\n");
		sleep(1);
		exit(0);
	}
	_lwt_tcb* target_tcb = &lwt_lst_root[target];
	assert((target_tcb->lwt_status == _LWT_STAT_RDY)||(target_tcb->lwt_status == _LWT_STAT_ZOMB));
	if(target == lwt_rdyq_head)
	{
		lwt_rdyq_head = target_tcb -> rdyq_next;
		lwt_lst_root[lwt_rdyq_head].rdyq_prev = _LWT_NULL;
	}else if (target == lwt_rdyq_tail)
	{
		lwt_rdyq_tail = target_tcb -> rdyq_prev;
		lwt_lst_root[lwt_rdyq_tail].rdyq_next = _LWT_NULL;
	}
	else
	{
		lwt_lst_root[target_tcb->rdyq_prev].rdyq_next = target_tcb->rdyq_next;
		lwt_lst_root[target_tcb->rdyq_next].rdyq_prev= target_tcb->rdyq_prev;
	}
	target_tcb->rdyq_next = _LWT_NULL;
	target_tcb->rdyq_prev = _LWT_NULL;	

	length_of_rdyq--;


#ifdef DBG
	printf("thread %d: after rmv, length_of_rdyq:\t%d\n", current_tid, length_of_rdyq);
#endif
}



/**
 *	check if current thread status is _LWT_STAT_WAIT, then append it into rdyq.
 */
	static inline 
void __lwt_append_into_rdyq(lwt_t target)
{
#ifdef DBG
	printf("thread %d: __lwt_add_rdyq:\t%d\n", current_tid, target);
#endif
	_lwt_tcb* target_tcb = &lwt_lst_root[target];
	assert((target_tcb->lwt_status == _LWT_STAT_RDY)||(target_tcb->lwt_status == _LWT_STAT_ZOMB));
	if(lwt_rdyq_head== _LWT_NULL)
	{
		target_tcb->rdyq_next = _LWT_NULL;
		target_tcb->rdyq_prev = _LWT_NULL;
		lwt_rdyq_head = target;
		lwt_rdyq_tail = target;
	}else
	{
		target_tcb->rdyq_next = _LWT_NULL;
		target_tcb->rdyq_prev = lwt_rdyq_tail;
		lwt_lst_root[lwt_rdyq_tail].rdyq_next = target;
		lwt_rdyq_tail = target;
	}
	length_of_rdyq++;
#ifdef DBG
	printf("thread %d: after add, length_of_rdyq:\t%d\n", current_tid, length_of_rdyq);
#endif
}


/**
 *	check node status _LWT_STAT_DEAD, then append it into deadq
 */
	static inline 
void __lwt_append_into_deadq(lwt_t target)
{
#ifdef DBG
	printf("thread %d: __lwt_add_dq:\t%d\n", current_tid, target);
#endif
	_lwt_tcb* target_tcb = &(lwt_lst_root[target]);
	assert(target_tcb->lwt_status==_LWT_STAT_DEAD);
	if(lwt_dead_head == _LWT_NULL)
	{
		target_tcb->deadq_next = _LWT_NULL;
		target_tcb->deadq_prev = _LWT_NULL;
		lwt_dead_head = target;
		lwt_dead_tail = target;
	}else
	{
		target_tcb->deadq_next = _LWT_NULL;
		target_tcb->deadq_prev = lwt_dead_tail;
		lwt_lst_root[lwt_dead_tail].deadq_next = target;
		lwt_dead_tail = target;
	}
	length_of_deadq++;
}

/**
 *	Remove a node from deadq.
 */
	static inline 
void __lwt_remove_from_deadq()
{
#ifdef DBG
	printf("thread %d: __lwt_rmv_dq:\t%d\n", current_tid, lwt_dead_head);
#endif
	assert(length_of_deadq > 0);
	//this is the default behavior
	_lwt_tcb target_tcb = lwt_lst_root[lwt_dead_head];
	//1: move head pointer;
	lwt_dead_head = target_tcb.deadq_next;

	//2: manipulate pointers.
	lwt_lst_root[lwt_dead_head].deadq_prev = _LWT_NULL;
	target_tcb.deadq_next = _LWT_NULL;
	target_tcb.deadq_prev = _LWT_NULL;

	length_of_deadq--;
	if(length_of_deadq ==0)
	{
		lwt_dead_head = _LWT_NULL;
		lwt_dead_tail = _LWT_NULL;
	}
}


/**
 * This function should be called from the _INIT_LWT macro only.
 * This function will init an ampty _lwt_tcb on heap and return a
 * pointer to it.
 *
 * the new _lwt_tcb has its id as input parameter.
 *
 */
_lwt_tcb* __init_tcb(lwt_t id)
{

#ifdef DBG
	printf("thread %d: I'm in __init_tcb: \t%d\n", current_tid, id);
#endif
	_lwt_tcb* lwt_tmp = (_lwt_tcb*)&(lwt_lst_root[id]);

	/**
	 * get new thread info and store them into _lwt_tmp:
	 */

	//the main thread has thread id 0.
	lwt_tmp->lwt_id = id;
	lwt_tmp->lwt_ip = _LWT_REG_NSET;

	//set stack pointers
	//if this is main, then we don't need to manually assign a stack
	if(lwt_tmp->lwt_status == _LWT_STAT_DEAD)
	{
		//this is a reused block, just clear stack.
		//		memset(lwt_tmp->lwt_ebp, 0, _LWT_STACK_SIZE-50);
		lwt_tmp->lwt_ebp = lwt_tmp->ebp_base;
		lwt_tmp->lwt_esp = lwt_tmp->lwt_ebp;
		__lwt_remove_from_deadq(id);
		lwt_tmp->ret_val = 0;
	}else if(id != 0)	//this is a new one
	{
		//now we have the stack allocated and cleared. 
		char* stack = (void*)calloc(sizeof(char)*_LWT_STACK_SIZE, sizeof(char));
		lwt_tmp->lwt_ebp = stack +_LWT_STACK_SIZE;
		lwt_tmp->ebp_base = lwt_tmp->lwt_ebp;
		lwt_tmp->lwt_esp = lwt_tmp->lwt_ebp;
	}

	if(id == 0)
		lwt_tmp->parent = _LWT_NULL;
	else
		lwt_tmp->parent = current_tid;

	//this is to record whether this block as been joined by someone else or not
	lwt_tmp->joined = _LWT_NULL;

	//manipulating rdyq
	lwt_tmp->rdyq_next= _LWT_NULL;
	lwt_tmp->rdyq_prev= _LWT_NULL;
	lwt_tmp->deadq_next= _LWT_NULL;
	lwt_tmp->deadq_prev= _LWT_NULL;
	if(id==0)
	{
		lwt_tmp->lwt_status = _LWT_STAT_RUN;
	}
	else
	{
		lwt_tmp->lwt_status = _LWT_STAT_RDY;
		__lwt_append_into_rdyq(id);
	}

	lwt_tmp->ret_val = NULL;

	//waiting list
//	lwt_tmp->wait_cnt = 0;		//this one is waiting for no one.

	lwt_tmp->chan_data = NULL;
	lwt_tmp->dock1 = NULL;
	lwt_tmp->dock2 = NULL;
	
	num_of_threads++;


	return lwt_tmp;
}




/**
 *	__lwt_schedule will choose the next target,
 *	save current content, 
 *	manipulate queues, then calls __lwt_dispatch
 *
 */
void  __lwt_schedule(lwt_t target)
{

#ifndef DBG
	assert(lwt_lst_root[target].lwt_status == _LWT_STAT_ZOMB ||
			lwt_lst_root[target].lwt_status == _LWT_STAT_RUN);
#endif

#ifdef DBG
	
	if(!(lwt_lst_root[target].lwt_status == _LWT_STAT_ZOMB ||
			lwt_lst_root[target].lwt_status == _LWT_STAT_RUN))
	{
		printf("schedule target %d with unexpected status: %d\n",
				target,
				lwt_lst_root[target].lwt_status);
		exit(0);
	}
#endif


#ifdef DBG
	printf("thread %d: I'm calling __lwt_schedule:%d\n", current_tid, target);
#endif
	_lwt_tcb* curr = &lwt_lst_root[current_tid];
	current_tid = target;
	__lwt_dispatch(&lwt_lst_root[target], curr);

#ifndef DBG
	assert(lwt_lst_root[current_tid].lwt_status == _LWT_STAT_ZOMB ||
			lwt_lst_root[current_tid].lwt_status == _LWT_STAT_RUN);
#endif

#ifdef DBG
	
	if(!(lwt_lst_root[current_tid].lwt_status == _LWT_STAT_ZOMB ||
			lwt_lst_root[current_tid].lwt_status == _LWT_STAT_RUN))
	{
		printf("back from schedule, thread %d with unexpected status: %d\n",
				current_tid,
				lwt_lst_root[current_tid].lwt_status);
		exit(0);
	}
#endif

	return;

}

void __lwt_free(lwt_t target)
{
	num_of_threads--;
}

int __lwt_get_rdyq_len()
{
	return length_of_rdyq;
}

int __lwt_get_thd_num()
{
	return num_of_threads;
}

/*****************************************************************************
 ***************	Following are functions used by channel. *****************
 *****************************************************************************/

/**
 *	This function will trigger an event.
 *	After triger the event, it blocked.
 *	This will be a pending event.
 *
 */
void __lwt_chan_triger_evnt(lwt_chan_t c, int type)
{
	lwt_cgrp_t cg = c->cgrp;
	if(unlikely(cg == NULL))
		return;
#ifdef DBG
	printf("thread %d: event trigger: %d in channel 0x%08x.\n",
			current_tid, type, (unsigned int)c);
#endif

	assert(cg->evnt_cnt<= _LWT_MAX_EVNT_SZ);

	cg->evnt_arr[cg->prod_p] = type;
	cg->prod_p = (++(cg->prod_p))%_LWT_MAX_EVNT_SZ;
	cg->evnt_cnt++;

	if(cg->waiter != _LWT_NULL)
	{
#ifdef DBG
		printf("Thread %d: cg 0x%08x has as waiter: %d\n", 
				current_tid, (unsigned int)cg, cg->waiter);
#endif
		assert(lwt_lst_root[cg->waiter].lwt_status == _LWT_STAT_WAIT );
		lwt_t waiter = cg->waiter;
		lwt_lst_root[waiter].dock1 = (void*)c;

		cg->waiter = _LWT_NULL;

		lwt_lst_root[current_tid].lwt_status = _LWT_STAT_RDY;
		__lwt_append_into_rdyq(current_tid);

		lwt_lst_root[waiter].lwt_status = _LWT_STAT_RUN;
		__lwt_schedule(waiter);

	}else{
#ifdef DBG
		printf("Thread %d: cg 0x%08x has no waiter, make pending event.\n",
				current_tid, (unsigned int)cg);
#endif
	}

	return;

}

void __lwt_chan_rem_event(lwt_cgrp_t cg)
{
	if(unlikely(cg == NULL))
		return;
	if(cg->evnt_cnt == 0)
		return;
	cg->evnt_arr[cg->cons_p] = 0;
	cg->cons_p = (++(cg->cons_p)) % _LWT_MAX_EVNT_SZ;
	cg->evnt_cnt--;
}


/**
 * This function takes a lwt_chan_t as parameter, return the target data packet.
 * 1: assert: current_tid == c->receiver;
 * 2: see if there is any data on data buffer:
 * 		while(buf_len == 0 && blocked_len == 0)	
 * 			2.1: mark myself as WAIT.
 * 			2.2: yield(_LWT_NULL);		//so current receiver thread will be blocked
 * 		//reach out here, means either buf_len>0 or blocked_len > 0
 * 		if buf_len > 0
 *			2.1: get data_buf[cons_p];
 *			2.2: cons_p ++;
 * 			2.3: buf_len --;
 * 			if blocked_len > 0
 * 				2.4: remove a sender from blocked senders list
 * 				2.5: blocked_len--;
 * 				2.6: put target_tcb->chan_data into data_buf[prod_p];
 * 				2.7: buf_len ++;
 * 				2.8: mark target_tcb as RDY;
 * 				2.9: put target_tcb into rdyq;
 * 		else	//no buf_len, but has blocked.
 * 			2.1: get the first thread from blocked_senders
 * 			2.2: get the data packet from tcb
 * 			2.3: unblock sender:
 * 				2.3.1: turn sender status into RDY
 * 				2.3.2: put sender into rdyq
 * 			2.5: continue executes, return the copied data packet.
 *
 */
inline void*
__lwt_chann_remove_from_data_buf(lwt_chan_t c)
{
#ifdef DBG
	printf("thread %d: attempting to remove data from channel 0x%08x\n", 
			current_tid, (unsigned int) c);
#endif
	void* data = NULL;
	linked_buf* tmp = NULL;
	//1
	assert(current_tid == c->receiver);
	//2
	while(c->buf_len == 0 && c->blocked_len == 0)
	{
#ifdef DBG
		printf("thread %d: no data/blocked in channel 0x%08x, blocking...\n",
				current_tid, (unsigned int)c);
#endif
		lwt_t operand;
		//2.1:
		lwt_lst_root[current_tid].lwt_status = _LWT_STAT_WAIT;
		//2.2:
		operand = lwt_rdyq_head;
		__lwt_remove_from_rdyq(operand);
		lwt_lst_root[operand].lwt_status = _LWT_STAT_RUN;

		__lwt_schedule(operand);
#ifdef DBG
		printf("thread %d: awake and check if any data avaliable in channel 0x%08x\n",
				current_tid, (unsigned int)c);
#endif
		
	}
	//reach out here, means either buf_len>0 or blocked_len > 0
	
	if(c->buf_len>0)
	{

#ifdef DBG
		printf("thread %d: data found in channel 0x%08x\n",
				current_tid, (unsigned int) c);
#endif
		//2.1
		data = (*(void* (*)[c->buf_sz])(c->data_buf))[c->cons_p];
		//2.2
		c->cons_p = (++(c->cons_p)) % c->buf_sz;
		//2.3
		c->buf_len--;
		if(c->blocked_len > 0)
		{
			//2.4
			tmp = c->blocked_senders;
			c->blocked_senders = c->blocked_senders->next;
			//2.5
			c->blocked_len--;
			if(c->blocked_len == 0)
				c->blocked_senders_last = nil;
			//2.6
			(*(void* (*)[c->buf_sz])(c->data_buf))[c->prod_p] = ((_lwt_tcb*)(tmp->self))->chan_data;
			c->prod_p = (++c->prod_p)%(c->buf_sz);
			//2.7
			c->buf_len++;
#ifdef DBG
			printf("thread %d: found blocked sender %d, data put in buffer, append into rdyq.\n",
					current_tid, ((_lwt_tcb*)(tmp->self))->lwt_id);
#endif

			//2.8
			((_lwt_tcb*)(tmp->self))->lwt_status = _LWT_STAT_RDY;
			//2.9
			__lwt_append_into_rdyq(((_lwt_tcb*)(tmp->self))->lwt_id);
		}
	}else{
		//2.1
		tmp = c->blocked_senders;
#ifdef DBG
			printf("thread %d: no data found, but find blocked sender %d, append into rdyq.\n",
					current_tid, ((_lwt_tcb*)(tmp->self))->lwt_id);
#endif
		c->blocked_senders = c->blocked_senders->next;
		c->blocked_len--;
		if(c->blocked_len == 0)
			c->blocked_senders_last = nil;
		//2.2
		data = (((_lwt_tcb*)(tmp->self))->chan_data);
		//2.3.1
		((_lwt_tcb*)(tmp->self))->lwt_status = _LWT_STAT_RDY;
		//2.3.2
		__lwt_append_into_rdyq(((_lwt_tcb*)(tmp->self))->lwt_id);


		//2.5
	}

//	if(tmp != NULL)
//		free(tmp);
	return data;

}

/**
 *	0.1: if target thread is dead or zombie, return -1;
 *	0.2: if target thread is already derefed, return -1;
 *	0.5:
 *	trigger event.
 *	1: check channel status
 *		if channel data buffer not full:
 *		2.1: append data onto data_buf
 *		2.2: returns
 *		else:	//channel data buffer is full:
 *		2.1: append self into blocked senders list
 *		-2.2: turn myself into WAIT status
 *		2.3: yield(receiver);	//this will unblock the receiver if
 *							//the receiver is waiting the channel
 *		2.4: after back, means the message has been
 *			successfully received, send succeed, means the sender's block
 *			will be nolonger needed, free it.
 *
 *	4: return.
 *
 */
inline int 
__lwt_chann_append_into_data_buf(lwt_chan_t c, void* data_pkt)
{

#ifdef DBG
	printf("thread %d: attempting to add data into channel 0x%08x\n", 
			current_tid, (unsigned int) c);
#endif

	int full = (c->buf_len == c->buf_sz);
	//0.1
	if(!(lwt_lst_root[c->receiver].lwt_status == _LWT_STAT_WAIT ||
				lwt_lst_root[c->receiver].lwt_status == _LWT_STAT_RDY))
	{
#ifdef DBG
		printf("thread %d: channel 0x%08x has receiver %d in invalid status: %d\n",
				current_tid, (unsigned int)c, c->receiver, 
				lwt_lst_root[c->receiver].lwt_status);
#endif
		return -1;
	}
	//0.2
	if(unlikely(c->receiver == _LWT_NULL))
	{
#ifdef DBG
		printf("thread %d: channel receiver has called deref!\n",
				current_tid);
#endif
		return -1;
	}
	//0.5:
	__lwt_chan_triger_evnt(c, _LWT_CHAN_EVNT_READ_AVBL);
	//1:
	if(!full)
	{
#ifdef DBG
		printf("thread %d: channel 0x%08x data buffer is not full, length: %d; sz: %d.\n",
				current_tid, (unsigned int)c, c->buf_len, c->buf_sz);
#endif
		//2.1
		(*(void* (*)[c->buf_sz])(c->data_buf))[c->prod_p] = data_pkt;
		//we don't need to check if new prod_p is overwriting cons_p or not,
		//because we have buf_len.
		c->prod_p = (++c->prod_p)%(c->buf_sz);
		c->buf_len ++;
		if(unlikely(lwt_lst_root[c->receiver].lwt_status == _LWT_STAT_WAIT))
		{
#ifdef DBG
			printf("thread %d: data appeared, put receiver %d into rdyq\n",
					current_tid, c->receiver);
#endif

			lwt_lst_root[c->receiver].lwt_status = _LWT_STAT_RDY;
			__lwt_append_into_rdyq(c->receiver);
		}


	}
	else
	{
#ifdef DBG
		printf("thread %d: channel 0x%08x data buffer full, append into blocked list,\n",
				current_tid, (unsigned int) c);
#endif
		//2.1:
		linked_buf* tmp = (linked_buf*)malloc(sizeof(linked_buf*));
		tmp->self = (void*)&(lwt_lst_root[current_tid]);
		tmp->next = nil;
		if(c->blocked_len == 0)
		{
			c->blocked_senders = tmp;
			c->blocked_senders_last = tmp;
			c->blocked_senders_last->next = nil;
		}else{
			c->blocked_senders_last->next = tmp;
			c->blocked_senders_last = tmp;
		}
		c->blocked_len++;
		__lwt_chan_rem_event(c->cgrp);

#ifdef DBG
		printf("thread %d: pick thread %d as target\n",
				current_tid, c->receiver);
#endif
		lwt_t target = c->receiver;

		assert(lwt_lst_root[target].lwt_status == _LWT_STAT_RDY || 
				lwt_lst_root[target].lwt_status == _LWT_STAT_WAIT);
#ifdef DBG
		printf("thread %d: turn myself into WAIT status.\n", current_tid);
#endif
		lwt_lst_root[current_tid].lwt_status = _LWT_STAT_WAIT;
		//4:
		if(lwt_lst_root[target].lwt_status == _LWT_STAT_RDY)
		{
#ifdef DBG
		printf("thread %d: target %d is in rdy status, rm from rdyq.\n",
				current_tid, target);
#endif
			__lwt_remove_from_rdyq(target);
		}else{
#ifdef DBG
		printf("thread %d: target %d is in WAIT status, wake up\n",
				current_tid, target);
#endif
		}

		lwt_lst_root[target].lwt_status = _LWT_STAT_RUN;

#ifdef DBG
		printf("thread %d: scheduled into thread %d\n",
				current_tid, target);
#endif
		__lwt_schedule(target);

		//2.4:
		free(tmp);
	}
	//4
	return 1;
}

	
inline int 
__lwt_chann_append_into_sndr_buf(lwt_chan_t c, lwt_t sender)
{
	//target channel has invalid receiver
	if(unlikely(c->receiver == _LWT_NULL))
		return -1;
#ifdef DBG
	printf("thread %d: thread %d append onto blocked list of channel 0x%08x\n",
			current_tid, sender, (unsigned int) c);
#endif

	linked_buf* curr = c->blocked_senders;
	linked_buf* prev = nil;
	while(curr != nil)
	{
		//already in sender list
		if(unlikely(((_lwt_tcb*)(curr->self))->lwt_id == sender ))
			return -1;
		prev = curr;
		curr = curr->next;
	}
	linked_buf *tmp = (linked_buf*)malloc(sizeof(linked_buf));
	tmp->self = &(lwt_lst_root[sender]);
	tmp->next = nil;

	//to here, curr will points to the last nil node.
	if(prev == nil)	//the sender is the first sender in the buffer
		c->senders = tmp;
	else
		prev->next = tmp;
	c->snd_cnt++;

	return 0;
}



#endif
